#include "main_scan.h"
#include "ui_main_scan.h"
#include <QObject>
#include<QThread>
#include<QMutex>
#include<bits/stdc++.h>
#include<QTcpSocket>
#include<QUdpSocket>
#include<QDateTime>
QMutex* main_scan::mtx=nullptr;
main_scan::main_scan(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::main_scan)
{
    ui->setupUi(this);
    p_set=new parameter_set;
    std::srand((unsigned int)time(nullptr));
    connect(p_set,&parameter_set::paramater_end_set,this,&main_scan::get_parameter_end_set_result);
    connect(this,&main_scan::has_all_exited,this,&main_scan::m_exited);
    connect(this,&main_scan::exit_tip,this,&main_scan::exit_display);
    connect(this,&main_scan::p_exit,this,&main_scan::g_exit);
    task_cnt=0;
    ui->scan_save_pbn->setEnabled(false);
    started_cnt=0;
    paused_cnt=0;
    stopped_cnt=0;
    base_t=100;
    res_cnt=0;
    total_task_cnt=0;
    exited=false;
    ui->display_close_port->setChecked(true);
    ui->display_open_port->setChecked(true);
    ui->display_close_port->setEnabled(false);
    ui->display_open_port->setEnabled(false);
    ui->scan_condition_flush_pbn->setEnabled(false);
    main_scan::mtx=new QMutex;
    q=new std::queue<scan_thread*>;
    scan_condition_body="";
    open_=new std::vector<std::pair<std::pair<QString,int>,std::pair<QString,bool>>>;
    close_=new std::vector<std::pair<std::pair<QString,int>,std::pair<QString,bool>>>;
    query_bank=new std::map<std::pair<QString,int>,QString>;
    connect(this,&main_scan::draw_scan_condition,this,&main_scan::get_draw_scan_condition_inform);
    //new 10 threads
    for(int i=0;i<2000;i++){
        auto *tmp=new scan_thread([&](std::pair<std::pair<QString,int>,std::pair<QString,bool>>x){
            QString sc_cond="IP:"+x.first.first+" Port:"+QString::number(x.first.second)+" 类型:"+x.second.first+" 状态:";
            if(x.second.second)sc_cond+="open";
            else sc_cond+="close";
            int len=0;
            scan_thread::msleep(base_t<<1);
            scan_thread::mutex->lock();
            main_scan::mtx->lock();
            ui->progress_line->setText(QString::number(++task_cnt)+"/"+QString::number(total_task_cnt));
            main_scan::mtx->unlock();
            QThread::msleep(100);
            scan_thread::mutex->unlock();
            QThread::msleep(base_t+(base_t>>1));
            main_scan::mtx->lock();
            scan_condition_body+=sc_cond+"\n";
            len=scan_condition_body.length();
            main_scan::mtx->unlock();
            QThread::msleep(base_t+(base_t>>1));
            scan_thread::mutex->lock();
            main_scan::mtx->lock();
            if(len>1000){
                emit main_scan::draw_scan_condition(scan_condition_body);
                scan_condition_body="";
                QThread::msleep(100);
            }
            main_scan::mtx->unlock();
            QThread::msleep(100);
            scan_thread::mutex->unlock();
            main_scan::mtx->lock();
            query_bank->insert({x.first,sc_cond});
            if(x.second.second)open_->push_back(x);
            else close_->push_back(x);
            main_scan::mtx->unlock();
            QThread::msleep(base_t+(base_t>>1));
        });
        connect(tmp,&scan_thread::has_started,this,&main_scan::get_started_inform);
        connect(tmp,&scan_thread::has_stopped,this,&main_scan::get_stop_inform);
        connect(tmp,&scan_thread::has_paused,this,&main_scan::get_pause_inform);
        q->push(tmp);
    }

}

main_scan::~main_scan()
{
    delete ui;
}

void main_scan::on_parameter_set_pbn_clicked()
{
    ui->parameter_now_choosed_display_field->clear();
    this->hide();
    p_set->show();
}

void main_scan::get_parameter_end_set_result(QStringList ip_list,std::pair<int,int>conseq_ports,std::vector<int>ports,int thread_cnt)
{
    QThread::msleep(300);
    ui->display_close_port->setChecked(true);
    QThread::msleep(300);
    ui->display_open_port->setChecked(true);
    QThread::msleep(300);
    ui->display_close_port->setEnabled(false);
    QThread::msleep(300);
    ui->display_open_port->setEnabled(false);
    QThread::msleep(300);
    ui->scan_condition_flush_pbn->setEnabled(false);
    QThread::msleep(300);
    ui->scan_save_pbn->setEnabled(false);
    QThread::msleep(300);
    open_=new std::vector<std::pair<std::pair<QString,int>,std::pair<QString,bool>>>;
    close_=new std::vector<std::pair<std::pair<QString,int>,std::pair<QString,bool>>>;
    query_bank=new std::map<std::pair<QString,int>,QString>;
    bank=new std::vector<scan_thread*>;
    task_cnt=0;
    started_cnt=0;
    paused_cnt=0;
    stopped_cnt=0;
    base_t=100;
    res_cnt=0;
    total_task_cnt=0;
    scan_condition_body="";
    QThread::msleep(300);
    ui->parameter_now_choosed_display_field->clear();
    thd_cnt=thread_cnt;
    QThread::msleep(300);
    ui->progress_line->clear();
    QThread::msleep(300);
    ui->query_ip_line->clear();
    QThread::msleep(300);
    ui->query_port_line->clear();
    QThread::msleep(300);
    ui->prompt_field->clear();
    QThread::msleep(300);
    ui->scan_condition_field->clear();
    QThread::msleep(300);
    p_set->hide();
    QThread::msleep(300);
    this->show();
    qDebug()<<"ip:";
    for(auto x:ip_list){
        qDebug()<<x;
    }
    qDebug()<<"conseq_ports:";
    qDebug()<<conseq_ports.first<<'-'<<conseq_ports.second;
    qDebug()<<"discreet ports:";
    for(auto x:ports){
        qDebug()<<x;
    }
    qDebug()<<"threads_count: "<<thread_cnt;
    QThread::msleep(300);
    ui->parameter_now_choosed_display_field->append("当前设置的ip:");
    for(auto x:ip_list){
        ui->parameter_now_choosed_display_field->append(x);
    }
    QThread::msleep(300);
    ui->parameter_now_choosed_display_field->append("当前设置的端口:");
    QThread::msleep(300);
    ui->parameter_now_choosed_display_field->append("连续端口:");
    if(conseq_ports.first>=1)ui->parameter_now_choosed_display_field->append(QString::number(conseq_ports.first)+"-"+QString::number(conseq_ports.second)+"端口");
    else ui->parameter_now_choosed_display_field->append("无");
    QThread::msleep(300);
    ui->parameter_now_choosed_display_field->append("离散端口:");
    QString tmp="";
    for(auto x:ports){
        if(tmp.length()>0)tmp+=","+QString::number(x);
        else tmp=QString::number(x);
    }
    QThread::msleep(300);
    if(tmp.length()>0)ui->parameter_now_choosed_display_field->append(tmp);
    else ui->parameter_now_choosed_display_field->append("无");
    QThread::msleep(300);
    ui->parameter_now_choosed_display_field->append("当前设置的线程数:");
    QThread::msleep(300);
    ui->parameter_now_choosed_display_field->append(QString::number(thread_cnt));
    //base_t=base_t*(thread_cnt/10)+base_t;
    std::pair<int,std::vector<std::vector<std::pair<QString,int>>>>task_=scan_thread::init(ip_list,conseq_ports,ports,base_t,thread_cnt);
    QThread::msleep(300);
    total_task_cnt=task_.first;
    int ans=0;
    for(int i=0;i<thread_cnt;i++){
        auto *tmp=q->front();q->pop();
        bank->push_back(tmp);
    }
    for(int i=0;i<thread_cnt;i++){
        auto *tmp=(*bank)[i];
        tmp->setRand_num(base_t+(i<<6));
        tmp->setMytask(task_.second[i]);
        ans+=task_.second[i].size();
    }
    qDebug()<<ans<<' '<<bank->size()<<' '<<thd_cnt<<'\n';
}

bool f_s[3]={0,0,0};
void main_scan::get_started_inform()
{

    ui->scan_pause_pbn->setEnabled(false);
    started_cnt++;
    qDebug()<<started_cnt;
    if(!f_s[0]){
        main_scan::mtx->lock();
        ui->prompt_field->append("the first thread has started!");
        f_s[0]=true;
    }
    if(!f_s[1]&&started_cnt>=((thd_cnt-stopped_cnt)>>1)){
        ui->prompt_field->append("half of the thread has started!");
        f_s[1]=true;
    }
    if(!f_s[2]&&started_cnt==thd_cnt-stopped_cnt){
        ui->prompt_field->append("all of the thread has started!");
        for(int i=0;i<=2;i++)f_s[i]=false;
        started_cnt=0;
        ui->scan_pause_pbn->setEnabled(true);
        ui->scan_break_pbn->setEnabled(true);
        ui->scan_exit_pbn->setEnabled(true);
        main_scan::mtx->unlock();
    }
    scan_thread::msleep(50);
}

bool pause_f1=false,pause_f2=false;;
void main_scan::get_pause_inform()
{
    main_scan::mtx->lock();
    paused_cnt++;
    qDebug()<<paused_cnt;
    if(!pause_f1){
        ui->prompt_field->append("the threads start to pause");
        pause_f1=true;
    }
    if(!pause_f2&&paused_cnt>((thd_cnt-stopped_cnt)>>1)){
        ui->prompt_field->append("half of the threads has paused");
        pause_f2=true;
    }
    if(paused_cnt==thd_cnt-stopped_cnt){
        paused_cnt=0;
        ui->scan_pause_pbn->setEnabled(true);
        ui->prompt_field->append("all of the threads has paused");
        pause_f1=false;
        pause_f2=false;
    }
    main_scan::mtx->unlock();
}

bool has_half_stop=false;
void main_scan::get_stop_inform()
{
    stopped_cnt++;
    qDebug()<<stopped_cnt;
    if(stopped_cnt>thd_cnt/2){
        if(!has_half_stop)ui->prompt_field->append("half of the thread has stopped!"),has_half_stop=true;
    }
    if(stopped_cnt==thd_cnt){
        ui->prompt_field->append("all of the threads started has stopped!");
        has_half_stop=false;
        ui->scan_start_pbn->setEnabled(true);
        ui->parameter_reset_pbn->setEnabled(true);
        ui->parameter_set_pbn->setEnabled(true);
        QThread::msleep(300);
        main_scan::mtx->lock();
        emit main_scan::draw_scan_condition(scan_condition_body);
        scan_condition_body="";
        QThread::msleep(100);
        main_scan::mtx->unlock();
        main_scan::mtx->lock();
        ui->display_close_port->setEnabled(true);
        main_scan::mtx->unlock();
        QThread::msleep(300);
        main_scan::mtx->lock();
        ui->display_open_port->setEnabled(true);
        main_scan::mtx->unlock();
        QThread::msleep(300);
        main_scan::mtx->lock();
        ui->scan_condition_flush_pbn->setEnabled(true);
        main_scan::mtx->unlock();
        QThread::msleep(300);
        main_scan::mtx->lock();
        ui->scan_save_pbn->setEnabled(true);
        main_scan::mtx->unlock();
        QThread::msleep(300);
        main_scan::mtx->lock();
        std::sort(open_->begin(),open_->end(),[&](auto x,auto y){
            if(x.first.first<y.first.first)return true;
            if(x.first.first>y.first.first)return false;
            return x.first.second<y.first.second;
        });
        main_scan::mtx->unlock();
        QThread::msleep(300);
        main_scan::mtx->lock();
        std::sort(close_->begin(),close_->end(),[&](auto x,auto y){
            if(x.first.first<y.first.first)return true;
            if(x.first.first>y.first.first)return false;
            return x.first.second<y.first.second;
        });
        main_scan::mtx->unlock();
        QThread::msleep(300);
        if(exited){
            emit has_all_exited();
        }
    }
    scan_thread::msleep(100);
}


void main_scan::on_scan_start_pbn_clicked()
{
    scan_thread::mutex->lock();
    ui->prompt_field->append("程序正在慢启动，请稍候");
    qDebug()<<"???";
    scan_thread::msleep(1000);
    scan_thread::mutex->unlock();
    cl_scan_condition_field();
    ui->scan_start_pbn->setEnabled(false);
    ui->parameter_reset_pbn->setEnabled(false);
    ui->parameter_set_pbn->setEnabled(false);
    scan_thread::mutex->lock();
    for(auto x:*bank){
        //独占慢启动
        x->start();
    }
    scan_thread::mutex->unlock();
    /* for(int i=0;i<thd_cnt;i++){
        //慢启动
        scan_thread::mutex->lock();
        (*bank)[i]->start();
        scan_thread::mutex->unlock();
        QThread::msleep(200);
    }*/
}


void main_scan::on_parameter_reset_pbn_clicked()
{
    started_cnt=0;
    paused_cnt=0;
    stopped_cnt=0;
    task_cnt=0;
    ui->parameter_now_choosed_display_field->clear();
}


void main_scan::on_scan_condition_clear_pbn_clicked()
{
    cl_scan_condition_field();
}

void main_scan::get_draw_scan_condition_inform(QString x)
{
    // ui->scan_condition_field->append(x);
    // scan_thread::msleep(base_t<<1);
    /*while(scan_condition_queue.size()){
        ui->scan_condition_field->append(scan_condition_queue.front());
        scan_condition_queue.pop();
    }*/
    ui->scan_condition_field->append(x);
}

void main_scan::cl_scan_condition_field()
{
    scan_thread::mutex->lock();
    ui->scan_condition_field->clear();
    scan_thread::mutex->unlock();
}

bool f=false;
void main_scan::on_scan_pause_pbn_clicked()
{
    if(!f){
        scan_thread::sc_pause(),f=!f;
        ui->scan_pause_pbn->setText("继续");
        ui->scan_pause_pbn->setEnabled(false);
        ui->scan_break_pbn->setEnabled(false);
        ui->scan_exit_pbn->setEnabled(false);
        return;
    }
    else {
        scan_thread::sc_preceed(),f=!f;
        ui->scan_pause_pbn->setText("暂停");
        ui->scan_pause_pbn->setEnabled(false);
        return;
    }
}


void main_scan::on_scan_break_pbn_clicked()
{
    scan_thread::sc_stop();
}


void main_scan::on_query_clear_pbn_clicked()
{
    main_scan::mtx->lock();
    ui->query_ip_line->clear();
    ui->query_port_line->clear();
    main_scan::mtx->unlock();
}


void main_scan::on_query_pbn_clicked()
{
    int res=0;
    main_scan::mtx->lock();
    QString host_=ui->query_ip_line->text();
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->query_ip_line->setEnabled(false);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->query_port_line->setEnabled(false);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->query_pbn->setEnabled(false);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->query_clear_pbn->setEnabled(false);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    if(res==0&&!p_set->ip_valid(host_)){
        qDebug()<<host_;
        res=1;
    }
    main_scan::mtx->lock();
    QString pt=ui->query_port_line->text();
    main_scan::mtx->unlock();
    QThread::msleep(50);
    if(res==0&&!p_set->port_valid(pt)){
        res=2;
    }
    std::pair<QString,int>pp=std::make_pair(host_,pt.toInt());
    main_scan::mtx->lock();
    auto it=query_bank->find(pp);
    if(res==0&&it==query_bank->end()){
        res=3;
    }
    main_scan::mtx->unlock();
    QThread::msleep(50);
    if(res==0){
        main_scan::mtx->lock();
        ui->prompt_field->append("查询成功，结果如下：");
        main_scan::mtx->unlock();
        QThread::msleep(50);
        main_scan::mtx->lock();
        ui->prompt_field->append(it->second);
        main_scan::mtx->unlock();
        QThread::msleep(50);
    }else{
        if(res==1){
            main_scan::mtx->lock();
            ui->prompt_field->append("IP不合法！");
            main_scan::mtx->unlock();
            QThread::msleep(50);
            main_scan::mtx->lock();
            ui->query_ip_line->clear();
            main_scan::mtx->unlock();
            QThread::msleep(50);
        }else if(res==2){
            main_scan::mtx->lock();
            ui->prompt_field->append("端口不合法！");
            main_scan::mtx->unlock();
            QThread::msleep(50);
            main_scan::mtx->lock();
            ui->query_port_line->clear();
            main_scan::mtx->unlock();
            QThread::msleep(50);
        }else{
            main_scan::mtx->lock();
            ui->prompt_field->append("当前结果中没有目标！");
            main_scan::mtx->unlock();
            QThread::msleep(50);
            main_scan::mtx->lock();
            ui->query_port_line->clear();
            main_scan::mtx->unlock();
            QThread::msleep(50);
            main_scan::mtx->lock();
            ui->query_ip_line->clear();
            main_scan::mtx->unlock();
            QThread::msleep(50);
        }
    }
    main_scan::mtx->lock();
    ui->query_ip_line->setEnabled(true);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->query_port_line->setEnabled(true);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->query_pbn->setEnabled(true);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->query_clear_pbn->setEnabled(true);
    main_scan::mtx->unlock();
    QThread::msleep(50);
}


void main_scan::on_scan_condition_flush_pbn_clicked()
{
    main_scan::mtx->lock();
    //ui->scan_start_pbn->setEnabled(false);
    main_scan::mtx->unlock();
    QThread::msleep(300);
    main_scan::mtx->lock();
    ui->scan_condition_field->clear();
    main_scan::mtx->unlock();
    QThread::msleep(300);
    main_scan::mtx->lock();
    ui->prompt_field->append("正在刷新...");
    main_scan::mtx->unlock();
    QThread::msleep(300);
    QString ans;
    if(ui->display_open_port->isChecked()){
        ans="";
        for(auto x:*open_){
            QString sc_cond="IP:"+x.first.first+" Port:"+QString::number(x.first.second)+" 类型:"+x.second.first+" 状态:";
            if(x.second.second)sc_cond+="open";
            else sc_cond+="close";
            ans+=sc_cond+"\n";
        }
        main_scan::mtx->lock();
        emit main_scan::draw_scan_condition(ans);
        main_scan::mtx->unlock();
    }
    QThread::msleep(300);
    if(ui->display_close_port->isChecked()){
        ans="";
        for(auto x:*close_){
            QString sc_cond="IP:"+x.first.first+" Port:"+QString::number(x.first.second)+" 类型:"+x.second.first+" 状态:";
            if(x.second.second)sc_cond+="open";
            else sc_cond+="close";
            ans+=sc_cond+"\n";
        }
        main_scan::mtx->lock();
        emit main_scan::draw_scan_condition(ans);
        main_scan::mtx->unlock();
    }
    QThread::msleep(300);
    main_scan::mtx->lock();
    ui->prompt_field->append("已经刷新完毕！");
    main_scan::mtx->unlock();
    QThread::msleep(300);
}


void main_scan::on_scan_save_pbn_clicked()
{
    main_scan::mtx->lock();
    ui->scan_break_pbn->setEnabled(false);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->scan_pause_pbn->setEnabled(false);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->scan_start_pbn->setEnabled(false);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->scan_exit_pbn->setEnabled(false);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->query_ip_line->setEnabled(false);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->query_port_line->setEnabled(false);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->query_pbn->setEnabled(false);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->query_clear_pbn->setEnabled(false);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    //pause

    QString path="./"+QDateTime::currentDateTime().toString()+".json";
    path=path.remove(' ');
    std::ofstream file(path.toStdString());
    qDebug()<<path;
    file<<"{"<<'\n';
    std::unordered_map<QString,bool>exi;
    std::vector<QString>ips;
    for(auto x:*query_bank){
        if(exi[x.first.first])continue;
        exi[x.first.first]=true;
        ips.push_back(x.first.first);
    }//get all of the ip
    for(auto x:ips){
        QString key="\""+x+"\":{\n";
        file<<"  "<<key.toStdString();//2
        for(auto y:*open_){
            if(y.first.first==x){
                int pt=y.first.second;
                for(int i=0;i<key.length();i++)file<<' ';
                file<<"\""<<QString::number(pt).toStdString()<<"\":";
                QString res="tcp ";
                if(y.second.second){
                    res+="open";
                }else res+="close";
                file<<res.toStdString()<<"\n";
            }
        }
        for(auto y:*close_){
            if(y.first.first==x){
                int pt=y.first.second;
                for(int i=0;i<key.length();i++)file<<' ';
                file<<"\""<<QString::number(pt).toStdString()<<"\":";
                QString res="tcp ";
                if(y.second.second){
                    res+="open";
                }else res+="close";
                file<<res.toStdString()<<"\n";
            }
        }
    }
    file<<"}"<<'\n';
    ui->prompt_field->append("保存完毕！");

    //resume
    main_scan::mtx->lock();
    ui->scan_break_pbn->setEnabled(true);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->scan_pause_pbn->setEnabled(true);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->scan_start_pbn->setEnabled(true);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->scan_exit_pbn->setEnabled(true);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->query_ip_line->setEnabled(true);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->query_port_line->setEnabled(true);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->query_pbn->setEnabled(true);
    main_scan::mtx->unlock();
    QThread::msleep(50);
    main_scan::mtx->lock();
    ui->query_clear_pbn->setEnabled(true);
    main_scan::mtx->unlock();
    QThread::msleep(50);
}


void main_scan::on_scan_exit_pbn_clicked()
{
    exited=true;
    int tdc;
    main_scan::mtx->lock();
    tdc=thd_cnt;
    main_scan::mtx->unlock();
    QThread::msleep(500);
    if(tdc==stopped_cnt){
        emit has_all_exited();
    }else{
        emit ui->scan_break_pbn->clicked();
    }

}

void main_scan::m_exited()
{
    ui->prompt_field->setText("程序将在5秒之后退出!");
    emit exit_tip();
}

void main_scan::exit_display()
{
    for(int i=1;i<=5;i++){
        ui->prompt_field->append(QString::number(i));
        qDebug()<<i;
        QThread::msleep(100);
    }
    emit p_exit();
}

void main_scan::g_exit()
{
    p_set->close();
    this->close();
}



